﻿using System;
using System.Collections.Generic;
using Framework.StringSplit;

namespace Framework.FluentTextStringBuilder
{
    /// <summary>
    /// 
    /// </summary>
    public class TextStringBuilderFluent : ITextStringBuilderWriterFluent, ITextStringBuilderConfigurationFluent
    {
        // *********************************************************************************
        // Properties
        // *********************************************************************************
        public TextStringBuilder Instance { get; set; }

        // *********************************************************************************
        // C'tor
        // *********************************************************************************

        public TextStringBuilderFluent()
        {
            // Instance that this fluent provider is targeting
            Instance = new TextStringBuilder();

            ConfigSettings();
        }

        // *********************************************************************************
        // Overrides
        // *********************************************************************************

        public override string ToString()
        {
            return Instance.ToString();
        }

        // *********************************************************************************
        // Access to Writer & Configuration
        // *********************************************************************************

        public ITextStringBuilderConfigurationFluent Config()
        {
            return this;
        }

        /// <summary>
        /// Swich context Configs this instance.
        /// </summary>
        /// <param name="indentPosition">The indent position.</param>
        /// <param name="indentText">The indent text.</param>
        /// <param name="newLine">The new line.</param>
        /// <param name="dividerCharacter">The divider character.</param>
        /// <param name="dividerlength">The dividerlength.</param>
        /// <param name="nameValueSeperater">The name value seperater.</param>
        /// <param name="nameValuePadding">The name value padding.</param>
        /// <param name="propertyDelimiter">The property delimiter.</param>
        /// <param name="enclosureHasIndentation">if set to <c>true</c> [enclosure has indentation].</param>
        /// <param name="enclosureHasNewLine">if set to <c>true</c> [enclosure has new line].</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent ConfigSettings
            (
                int indentPosition = 0,
                string indentText = "    ",
                string newLine = FrameworkConstant.CRLF,
                char dividerCharacter = '-',
                int dividerlength = 100,
                string nameValueSeperater = ": ",
                int nameValuePadding = 30,
                ReplacePropertyDelimiterType propertyDelimiter = ReplacePropertyDelimiterType.Brace,
                bool enclosureHasIndentation = true,
                bool enclosureHasNewLine = true
            )
        {
            SetIndent(indentPosition);
            SetIndentText(indentText);
            SetDividerCharacter(dividerCharacter);
            SetDividerLength(dividerlength);
            SetNewLine(newLine);
            SetTemplatePropertyDelimiter(propertyDelimiter);
            SetNameValueSeperator(nameValueSeperater);
            SetNameValuePadding(nameValuePadding);
            SetEnclosureHasIndentation(enclosureHasIndentation);
            SetEnclosureHasNewLine(enclosureHasNewLine);

            return this;
        }

        public ITextStringBuilderWriterFluent Print()
        {
            _.P(ToString());

            return this;
        }

        public ITextStringBuilderWriterFluent Writer()
        {
            return this;
        }


        // *********************************************************************************
        // Implementation - Writer
        // *********************************************************************************

        // *********************************************************************************
        // Indent
        // *********************************************************************************

        /// <summary>
        /// Indents to the specified position.
        /// </summary>
        /// <param name="indentPosition"></param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent Indent(int indentPosition)
        {
            Instance.Indent = indentPosition;

            return this;
        }

        /// <summary>
        /// Indents to the left (1 position).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IndentLeft()
        {
            return IndentLeft(1);
        }

        /// <summary>
        /// Indents to the left (Outdent).
        /// </summary>
        /// <param name="indentOffset">The indent offset.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IndentLeft(int indentOffset)
        {
            Instance.Indent -= indentOffset;

            return this;
        }

        /// <summary>
        /// Indents to the right (1 position).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IndentRight()
        {
            return IndentRight(1);
        }

        /// <summary>
        /// Indents to the right.
        /// </summary>
        /// <param name="indentOffset">The indent offset.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IndentRight(int indentOffset)
        {
            Instance.Indent += indentOffset;

            return this;
        }

        // *********************************************************************************
        // Open/Close container
        // *********************************************************************************

        public bool EnclosureHasIndentation { get; set; }
        public bool EnclosureHasNewLine { get; set; }

        public ITextStringBuilderConfigurationFluent SetEnclosureHasIndentation(bool isIndent)
        {
            EnclosureHasIndentation = isIndent;

            return this;
        }

        public ITextStringBuilderConfigurationFluent SetEnclosureHasNewLine(bool isNewLine)
        {
            EnclosureHasNewLine = isNewLine;

            return this;
        }

        public ITextStringBuilderWriterFluent EnclosureOpen(string value)
        {
            if (EnclosureHasNewLine)
            {
                AddLine(value);
            }
            else
            {
                Add(value);
            }

            if (EnclosureHasIndentation)
            {
                IndentRight();
            }

            return this;
        }

        public ITextStringBuilderWriterFluent EnclosureClose(string value)
        {
            if (EnclosureHasIndentation)
            {
                IndentLeft();
            }

            if (EnclosureHasNewLine)
            {
                AddLine(value);
            }
            else
            {
                Add(value);
            }

            return this;
        }

        // *********************************************************************************
        // Add
        // *********************************************************************************

        public ITextStringBuilderWriterFluent Add(bool value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds a character to the text stream.</summary>
        /// <param name="value">The character to write. </param>
        public ITextStringBuilderWriterFluent Add(char value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds a character array to the text stream.</summary>
        /// <param name="value">The character array to write. </param>
        public ITextStringBuilderWriterFluent Add(char[] value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the text representation of a Double to the text stream.</summary>
        /// <param name="value">The double to write. </param>
        public ITextStringBuilderWriterFluent Add(double value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the text representation of an integer to the text stream.</summary>
        /// <param name="value">The integer to write. </param>
        public ITextStringBuilderWriterFluent Add(int value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the text representation of an 8-byte integer to the text stream.</summary>
        /// <param name="value">The 8-byte integer to write. </param>
        public ITextStringBuilderWriterFluent Add(long value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the text representation of an object to the text stream.</summary>
        /// <param name="value">The object to write. </param>
        public ITextStringBuilderWriterFluent Add(object value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the text representation of a Single to the text stream.</summary>
        /// <param name="value">The single to write. </param>
        public ITextStringBuilderWriterFluent Add(float value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the text representation of a Single to the text stream.</summary>
        /// <param name="value">The single to write. </param>
        public ITextStringBuilderWriterFluent Add(decimal value)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds the specified string to the text stream.</summary>
        /// <param name="value">The string to write. </param>
        public ITextStringBuilderWriterFluent Add(string value)
        {
            Instance.Write(value);

            return this;
        }

        public ITextStringBuilderWriterFluent Add(List<string> values)
        {
            foreach (var value in values)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>Adds out a formatted string, using the same semantics as specified.</summary>
        /// <param name="args">The argument array to output. </param>;
        /// <param name="format">The formatting string to use. </param>
        public ITextStringBuilderWriterFluent Add(string format, params object[] args)
        {
            Instance.Write(format, args);

            return this;
        }

        /// <summary>Adds a subarray of characters to the text stream.</summary>
        /// <param name="value">The character array to write data from. </param>;
        /// <param name="index">Starting index in the buffer. </param>
        /// <param name="count">The number of characters to write. </param>
        public ITextStringBuilderWriterFluent Add(char[] value, int index, int count)
        {
            Instance.Write(value);

            return this;
        }

        /// <summary>Adds a boolean to the text stream, followed by a line terminator.</summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent AddLine()
        {
            Instance.WriteLine();

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine();
        }

        // *********************************************************************************
        // AddLine
        // *********************************************************************************

        public ITextStringBuilderWriterFluent AddLine(bool value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, bool value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds a character to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The character to write. </param>
        public ITextStringBuilderWriterFluent AddLine(char value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, char value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds a character array to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The character array to write. </param>
        public ITextStringBuilderWriterFluent AddLine(char[] value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, char[] value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the text representation of a Double to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The double to write. </param>
        public ITextStringBuilderWriterFluent AddLine(double value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, double value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the text representation of an integer to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The integer to write. </param>
        public ITextStringBuilderWriterFluent AddLine(int value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, int value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the text representation of an 8-byte integer to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The 8-byte integer to write. </param>
        public ITextStringBuilderWriterFluent AddLine(long value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, long value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the text representation of an object to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The object to write. </param>
        public ITextStringBuilderWriterFluent AddLine(object value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, object value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the text representation of a Single to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The single to write. </param>
        public ITextStringBuilderWriterFluent AddLine(float value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, float value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the text representation of a Single to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The single to write. </param>
        public ITextStringBuilderWriterFluent AddLine(decimal value)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, decimal value)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        /// <summary>Adds the specified string to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The string to write. </param>
        public ITextStringBuilderWriterFluent AddLine(string value)
        {
            Instance.WriteLine(value);

            return this;
        }

        /// <summary>
        /// Adds the specified string to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <param name="value">The string to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, string value)
        {
            if (options.EnumIs(FTSBAddOptionType.RetainIndent))
            {
                RetainIndentWriteLine(value);
            }

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(List<string> values)
        {
            foreach (var value in values)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, List<string> values)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(values);
        }

        /// <summary>Adds out a formatted string, using the same semantics as specified.</summary>
        /// <param name="args">The argument array to output. </param>;
        /// <param name="format">The formatting string to use. </param>
        public ITextStringBuilderWriterFluent AddLine(string format, params object[] args)
        {
            Instance.WriteLine(format, args);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, string format, params object[] args)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(format, args);
        }

        /// <summary>Adds a subarray of characters to the text stream, followed by a line terminator.</summary>
        /// <param name="value">The character array to write data from. </param>;
        /// <param name="index">Starting index in the buffer. </param>
        /// <param name="count">The number of characters to write. </param>
        public ITextStringBuilderWriterFluent AddLine(char[] value, int index, int count)
        {
            Instance.WriteLine(value);

            return this;
        }

        public ITextStringBuilderWriterFluent AddLine(FTSBAddOptionType options, char[] value, int index, int count)
        {
            // If options make sense for this signature then put them in place, else delegate through to the standard AddLine
            return AddLine(value);
        }

        // *********************************************************************************
        // Add value, If condition is met
        // *********************************************************************************

        /// <summary>
        /// Adds if.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, bool value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a character to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The character to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, char value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a character array to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The character array to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, char[] value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of a Double to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The double to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, double value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of an integer to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The integer to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, int value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of an 8-byte integer to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The 8-byte integer to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, long value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of an object to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The object to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, object value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of a Single to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The single to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, float value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of a Single to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The single to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, decimal value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// Adds the specified string to the text stream.
        /// </summary>
        /// <param name="isTrue"></param>
        /// <param name="value">The string to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, string value)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds out a formatted string, using the same semantics as specified.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="format">The formatting string to use.</param>
        /// <param name="args">The argument array to output.</param>
        /// <returns></returns>
        /// ;
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, string format, params object[] args)
        {
            if (isTrue)
            {
                Instance.Write(format, args);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a subarray of characters to the text stream.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The character array to write data from.</param>
        /// <param name="index">Starting index in the buffer.</param>
        /// <param name="count">The number of characters to write.</param>
        /// <returns></returns>
        /// ;
        public ITextStringBuilderWriterFluent IfAdd(bool isTrue, char[] value, int index, int count)
        {
            if (isTrue)
            {
                Instance.Write(value);
            }

            return this;
        }

        // *********************************************************************************
        // Add value + line terminator, If condition is met
        // *********************************************************************************

        /// <summary>
        /// Adds line terminator to stream.
        /// </summary>
        /// <param name="isTrue"></param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue)
        {
            if (isTrue)
            {
                Instance.WriteLine();
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a boolean to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, bool value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a character to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The character to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, char value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a character array to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The character array to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, char[] value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of a Double to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The double to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, double value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of an integer to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The integer to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, int value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of an 8-byte integer to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The 8-byte integer to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, long value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of an object to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The object to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, object value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of a Single to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The single to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, float value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the text representation of a Single to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The single to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, decimal value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds the specified string to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The string to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, string value)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds out a formatted string, using the same semantics as specified.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="format">The formatting string to use.</param>
        /// <param name="args">The argument array to output.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, string format, params object[] args)
        {
            if (isTrue)
            {
                Instance.WriteLine(format, args);
            }

            return this;
        }

        /// <summary>
        /// If condition is met, Adds a subarray of characters to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="value">The character array to write data from.</param>
        /// <param name="index">Starting index in the buffer.</param>
        /// <param name="count">The number of characters to write.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfAddLine(bool isTrue, char[] value, int index, int count)
        {
            if (isTrue)
            {
                Instance.WriteLine(value);
            }

            return this;
        }

        // *********************************************************************************
        // IfIndent
        // *********************************************************************************

        /// <summary>
        /// Ifs the indent.
        /// </summary>
        /// <param name="isTrue">if set to <c>true</c> [is true].</param>
        /// <param name="indent">The indent.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent IfIndent(bool isTrue, int indent)
        {
            if (isTrue)
            {
                Indent(indent);
            }

            return this;
        }

        /// <summary>
        /// Indents to the left (1 position), if condition is met
        /// </summary>
        /// <param name="isTrue"></param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public ITextStringBuilderWriterFluent IfIndentLeft(bool isTrue)
        {
            if (isTrue)
            {
                IndentLeft();
            }

            return this;
        }

        /// <summary>
        /// Indents to the left, if condition is met
        /// </summary>
        /// <param name="isTrue"></param>
        /// <param name="indentPosition"></param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public ITextStringBuilderWriterFluent IfIndentLeft(bool isTrue, int indentPosition)
        {
            if (isTrue)
            {
                IndentLeft(indentPosition);
            }

            return this;
        }

        /// <summary>
        /// Indents to the right (1 position), if condition is met
        /// </summary>
        /// <param name="isTrue"></param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public ITextStringBuilderWriterFluent IfIndentRight(bool isTrue)
        {
            if (isTrue)
            {
                IndentRight();
            }

            return this;
        }

        /// <summary>
        /// Indents to the right, if condition is met
        /// </summary>
        /// <param name="isTrue"></param>
        /// <param name="indentPosition"></param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public ITextStringBuilderWriterFluent IfIndentRight(bool isTrue, int indentPosition)
        {
            if (isTrue)
            {
                IndentRight(indentPosition);
            }

            return this;
        }

        // *********************************************************************************
        // NameValue 
        // *********************************************************************************

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, string value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, int value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, float value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, decimal value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, double value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, bool value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, DateTime? value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValue(string name, Enum value)
        {
            Instance.WriteNameValue(name, value);

            return this;
        }

        // *********************************************************************************
        // NameValueLine
        // *********************************************************************************

        /// <summary>
        /// Adds name/value pair to the text stream, followed by a line terminator.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValueLine(string name, string value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        public ITextStringBuilderWriterFluent NameValueLine(string name, int value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        public ITextStringBuilderWriterFluent NameValueLine(string name, float value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        public ITextStringBuilderWriterFluent NameValueLine(string name, decimal value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        public ITextStringBuilderWriterFluent NameValueLine(string name, double value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        public ITextStringBuilderWriterFluent NameValueLine(string name, bool value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        public ITextStringBuilderWriterFluent NameValueLine(string name, DateTime? value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        /// <summary>
        /// Adds name/value pair to the text stream, followed by a line terminator.
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent NameValueLine(string name, Enum value)
        {
            Instance.WriteNameValueLine(name, value);

            return this;
        }

        // *********************************************************************************
        // Divider
        // *********************************************************************************

        /// <summary>
        /// Writes a dividing line to the text stream, followed by a line terminator.
        /// </summary>
        /// <param name="isTerminator">if set to <c>true</c> [is terminator].</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent Divider(bool isTerminator = true)
        {
            Instance.WriteDivider(isTerminator);

            return this;
        }

        /// <summary>
        /// Writes a dividing line to the text stream with a heading, followed by a line terminator.
        /// </summary>
        /// <param name="heading">The heading.</param>
        /// <param name="isTerminator">if set to <c>true</c> [is terminator].</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent Divider(string heading, bool isTerminator = true)
        {
            Instance.WriteDivider(heading, isTerminator);

            return this;
        }

        /// <summary>
        /// Writes the contents of a template using key/values supplied to expand the template tokens.
        /// </summary>
        /// <param name="template">The template.</param>
        /// <param name="keyValues">The key values.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent Template(string template, params string[] keyValues)
        {
            Instance.WriteExpandTemplate(template, keyValues);

            return this;
        }

        /// <summary>
        /// Writes the contents of a template using key/values supplied to expand the template tokens.
        /// </summary>
        /// <param name="template">The template.</param>
        /// <param name="keyValues">The key values.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent Template(string template, IDictionary<string, string> keyValues)
        {
            Instance.WriteExpandTemplate(template, keyValues);

            return this;
        }

        /// <summary>
        /// Writes the contents of a template using key/values supplied to expand the template tokens.
        /// </summary>
        /// <param name="template">The template.</param>
        /// <param name="tokenReplacer">The token replacer.</param>
        /// <returns></returns>
        public ITextStringBuilderWriterFluent Template(string template, ITokenReplacer tokenReplacer)
        {
            Instance.WriteExpandTemplate(template, tokenReplacer);

            return this;
        }

        public ITextStringBuilderWriterFluent AddFile(string fileName)
        {
            return AddFile(fileName, false);
        }

        public ITextStringBuilderWriterFluent AddFile(string fileName, bool isRetainIndent)
        {
            var content = FileUtil.Read(fileName);

            if (isRetainIndent)
            {
                RetainIndentWriteLine(content);
            }
            else
            {
                Instance.Write(content);
            }
            
            return this;
        }

        // *********************************************************************************
        // Implementation - Configuration
        // *********************************************************************************

        public ITextStringBuilderConfigurationFluent SetIndent(int indentPosition)
        {
            Instance.Indent = indentPosition;

            return this;
        }

        /// <summary>
        /// Sets the indent text (Defaults to "    ").
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetIndentText()
        {
            Instance.TabString = "    ";

            return this;
        }

        /// <summary>
        /// Sets the indent text.
        /// </summary>
        /// <param name="indentText">The indent text.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetIndentText(string indentText)
        {
            Instance.TabString = indentText;

            return this;
        }

        /// <summary>
        /// Sets the text to use when adding a new line (Default is Carriage Return/Line Feed).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetNewLine()
        {
            Instance.NewLine = FrameworkConstant.CRLF;

            return this;
        }

        /// <summary>
        /// Sets the text to use when adding a new line.
        /// </summary>
        /// <param name="newLine">The new line.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetNewLine(string newLine)
        {
            Instance.NewLine = newLine;

            return this;
        }

        /// <summary>
        /// Sets the name value seperator (Uses default seperator).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetNameValueSeperator()
        {
            Instance.NameValueSeperator = ": ";

            return this;
        }

        /// <summary>
        /// Sets the name value seperator.
        /// </summary>
        /// <param name="seperator">The seperator.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetNameValueSeperator(string seperator)
        {
            Instance.NameValueSeperator = seperator;

            return this;
        }

        /// <summary>
        /// Sets the name value padding (Uses default padding size).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetNameValuePadding()
        {
            Instance.NameValuePadding = 30;

            return this;
        }

        /// <summary>
        /// Sets the name value padding.
        /// </summary>
        /// <param name="padding">The padding.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetNameValuePadding(int padding)
        {
            Instance.NameValuePadding = padding;

            return this;
        }

        /// <summary>
        /// Sets the divider character (Uses default character).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetDividerCharacter()
        {
            Instance.LineCharacter = '-';

            return this;
        }

        /// <summary>
        /// Sets the divider character.
        /// </summary>
        /// <param name="dividerCharacter">The divider character.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetDividerCharacter(char dividerCharacter)
        {
            Instance.LineCharacter = dividerCharacter;

            return this;
        }

        /// <summary>
        /// Sets the length of the divider (Uses default character).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetDividerLength()
        {
            Instance.LineLength = 100;

            return this;
        }

        /// <summary>
        /// Sets the length of the divider.
        /// </summary>
        /// <param name="dividerlength">The divider length.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetDividerLength(int dividerlength)
        {
            Instance.LineLength = dividerlength;

            return this;
        }

        /// <summary>
        /// Sets the template property delimiter used when replacing delimited property names in a template (Uses default character).
        /// </summary>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetTemplatePropertyDelimiter()
        {
            Instance.ReplacePropertyDelimiter = ReplacePropertyDelimiterType.Brace;

            return this;
        }

        /// <summary>
        /// Sets the template property delimiter used when replacing delimited property names in a template.
        /// </summary>
        /// <param name="propertyDelimiter">The property delimiter.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent SetTemplatePropertyDelimiter(ReplacePropertyDelimiterType propertyDelimiter)
        {
            Instance.ReplacePropertyDelimiter = propertyDelimiter;

            return this;
        }

        /// <summary>
        /// Set Data object with a typesafe Key/Value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public ITextStringBuilderConfigurationFluent DataSet<T>(string key, T value)
        {
            Instance.DataSet(key, value);

            return this;
        }

        /// <summary>
        /// Splits content on cariage returns and retains the indent spacing when writing the lines.
        /// </summary>
        /// <param name="content">The content.</param>
        private void RetainIndentWriteLine(string content)
        {
            var lines = DelimitedUtil.SplitAsList(StringSplitOptionsType.None, content, new[] { FrameworkConstant.CRLF });

            foreach (var line in lines)
            {
                Instance.WriteLine(line);
            }
        }

    }
}